package com.sophialex.health.record.common.bind;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Text;

import com.sophia.pojo.AbstractModelObject;

public class CheckboxBindingUtil {
	protected Class<?> filedClass;

	protected boolean hasBeenUsed = false;

	/**
	 * 将复选框数组checks的可选中数目限制为limit
	 * 
	 * @param checks
	 *        待限制复选框数组
	 * @param limit
	 *        限制数
	 */
	public void limitCheckableCount(final Button[] checks, final int limit) {
		validateCheckBox(checks);

		// 判断初始选中状态是否满足条件
		if(getCheckedCount(checks) > limit) {
			throw new IllegalArgumentException("传入的复选框中已选中的数目超过了limit");
		}
		for(Button b : checks) {
			b.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					Button source = (Button) e.getSource();
					if(source.getSelection()) {
						if(getCheckedCount(checks) > limit) {
							source.setSelection(false);
						}
					}

				}

			});

		}
	}

	/**
	 * 根据复选框的选中状态启用/禁止文本框
	 * 
	 * @param b
	 *        具有SWT.CHECK风格的按钮(即复选框)
	 * @param t
	 *        要动态禁止/激活的文本框
	 * @param isEnableWhenChecked
	 *        为true时，b选中则t可用；为false时，b选中则t不可用
	 */
	public void bindTextState(final Button b, final Text t, final boolean isEnableWhenChecked) {
		if((b.getStyle() & SWT.CHECK) == 0) {
			throw new IllegalArgumentException("按钮必须具有SWT.CHECK风格.");
		}
		// 置文本框初始状态
		if(isEnableWhenChecked) {// isEnableWhenChecked=true表示b选中则t处于禁止状态
			t.setEnabled(b.getSelection());
		} else {
			t.setEnabled(!b.getSelection());
		}
		b.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				if(isEnableWhenChecked) {
					t.setEnabled(b.getSelection());
				} else {
					t.setEnabled(!b.getSelection());
				}
			}

		});
	}

	/**
	 * 利用复选框的选中状态拼接bean的属性值 注：一个CheckboxBindingUtil实例，该方法只能被调用一次
	 * 
	 * @param checks
	 *        :checkbox数组
	 * @param bean
	 *        :Model Bean
	 * @param proPath
	 *        :要绑定的bean的属性路径
	 * @param texts
	 *        :checks要显示的text的数组
	 * @param asc
	 *        :从低位还是从高位开始
	 */
	public void bindCheckBitByBit(final Button[] checks, final Object bean, final String proPath, String[] texts, final boolean asc) {

		if(hasBeenUsed)// 一个CheckboxBindingUtil实例，该方法只能被调用一次
			throw new IllegalStateException(this.getClass().getName() + "的每个实例的bindCheckBitByBit()方法只能被调用一次，请尝试构造新实例调用此方法");

		validateCheckBox(checks);
		if(texts != null && texts.length != checks.length) {
			throw new IllegalArgumentException("texts的长度必须与checks的长度相同");
		}

		final String[] beanPath = proPath.split("\\.");
		Object v = computeBeanPropValue(bean, beanPath);
		if(!filedClass.equals(Long.class) && !filedClass.equals(long.class)&& !filedClass.equals(String.class)) {
			throw new IllegalArgumentException(proPath + "所对应的属性必须为Long/long型");
		}
		if(v == null)
			v = "0";
		if(v.getClass().equals(String.class)&& ((String)v).trim().length()==0)
			v = "0";
		String sv = v+"";
		if(sv.trim().length()==0)sv="0";
		long proValue = Long.parseLong(sv);

		// 设置text
		if(texts != null) {
			for(int i = 0; i < checks.length; i++) {
				checks[i].setText(texts[i]);
			}
		}

		Object tmp = bean;
		if(beanPath.length > 1) {
			tmp = computeBeanPropValue(tmp, proPath.substring(0, proPath.lastIndexOf(".")).split("\\."));
		}
		final Object target = tmp;
		// if (!AbstractModelObject.class.isAssignableFrom(target.getClass())) {
		if(!(target instanceof AbstractModelObject)) {
			throw new IllegalArgumentException("bean必须是AbstractModelObject的子类");
		}
		final long mark = 1;
		// if(asc){
		for(int i = 0; i < checks.length; i++) {
			int j = i;
			if(!asc)
				j = checks.length - 1 - i;

			final int offset = j;
			if(((mark << offset) & proValue) == 0) {
				checks[i].setSelection(false);
			} else {
				checks[i].setSelection(true);
			}
			final Button b = checks[i];

			checks[i].addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {

					Object co = computeBeanPropValue(bean, beanPath);
					if(co == null)
						co = "0";
					if(co.getClass().equals(String.class)&& ((String)co).trim().length()==0)
						co = "0";
					long curValue = 0;
					try{
					curValue = Long.parseLong(co + "");
					}
					catch(Throwable e1){
						e1.printStackTrace();
					}
					long lastValue = 0;
					if(b.getSelection()) {
						lastValue = curValue | (mark << offset);

					} else {
						lastValue = curValue ^ (mark << offset);

					}
					setFieldValue(target, beanPath[beanPath.length - 1], lastValue, filedClass);

				}

			});
		}

		addBeanListener(target, beanPath, checks, asc);
		

		hasBeenUsed = true;
	}

	private void addBeanListener(Object target, String[] beanPath, final Button[] checks, final boolean asc) {
		if(!AbstractModelObject.class.isAssignableFrom(target.getClass()))
			return;
		((AbstractModelObject) target).addPropertyChangeListener(beanPath[beanPath.length - 1], new PropertyChangeListener() {

			public void propertyChange(PropertyChangeEvent evt) {
				Object ov = evt.getNewValue();
				if(ov == null)
					ov = "0";
				if(ov.getClass().equals(String.class) && ((String)ov).trim().length()==0)
					ov = "0";
				long value = Long.parseLong(ov + "");
				for(int i = 0; i < checks.length; i++) {
					int offset = i;
					if(!asc)
						offset = checks.length - 1 - i;
					if(((1 << offset) & value) == 0) {
						checks[i].setSelection(false);
					} else {
						checks[i].setSelection(true);
					}
				}
			}
		});

	}

	/**
	 * limitCheckableCount与bindCheckBitByBit的合成版
	 * 
	 * @param checks
	 * @param bean
	 * @param proPath
	 * @param texts
	 * @param asc
	 * @param limit
	 */
	// 这三个函数间存在大量的重叠逻辑，想重构，但有点乱，先放着
	public void bindCheckBitByBitAndLimitSelCount(final Button[] checks, final Object bean, final String proPath, String[] texts, final boolean asc, int limit) {
		if(hasBeenUsed)// 一个CheckboxBindingUtil实例，该方法只能被调用一次
			throw new IllegalStateException(this.getClass().getName() + "的每个实例的bindCheckBitByBit()方法只能被调用一次，请尝试构造新实例调用此方法");

		validateCheckBox(checks);

		// 判断初始选中状态是否满足条件
		if(getCheckedCount(checks) > limit) {
			throw new IllegalArgumentException("传入的复选框中已选中的数目超过了limit");
		}

		if(texts != null && texts.length != checks.length) {
			throw new IllegalArgumentException("texts的长度必须与checks的长度相同");
		}
		doBind(checks, bean, proPath, texts, asc, limit);

		hasBeenUsed = true;
	}

	private void doBind(final Button[] checks, Object bean, String proPath, String[] texts, boolean asc, final int limit) {
		final String[] beanPath = proPath.split("\\.");
		Object v = computeBeanPropValue(bean, beanPath);
		if(!filedClass.equals(Long.class) && !filedClass.equals(long.class)&& !filedClass.equals(String.class)) {
			throw new IllegalArgumentException(proPath + "所对应的属性必须为Long/long型");
		}
		if(v == null)
			v = "0";
		String sv = v+"";
		if(sv.trim().length()==0)sv="0";
		long proValue = Long.parseLong(sv);

		// 设置text
		if(texts != null) {
			for(int i = 0; i < checks.length; i++) {
				checks[i].setText(texts[i]);
			}
		}

		Object tmp = bean;
		if(beanPath.length > 1) {
			tmp = computeBeanPropValue(tmp, proPath.substring(0, proPath.lastIndexOf(".")).split("\\."));
		}
		final Object target = tmp;
		if(!AbstractModelObject.class.isAssignableFrom(target.getClass())) {
			throw new IllegalArgumentException("bean必须是AbstractModelObject的子类");
		}
		final long mark = 1;
		// if(asc){
		for(int i = 0; i < checks.length; i++) {
			int j = i;
			if(!asc)
				j = checks.length - 1 - i;

			final int offset = j;
			if(((mark << offset) & proValue) == 0) {
				checks[i].setSelection(false);
			} else {
				checks[i].setSelection(true);
			}
			final Button b = checks[i];

			checks[i].addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					Button source = (Button) e.getSource();
					if(source.getSelection()) {
						if(getCheckedCount(checks) > limit) {
							source.setSelection(false);
							return;
						}
					}
					Object co = computeBeanPropValue(target, beanPath);
					if(co == null)
						co = "0";
					long curValue = Long.parseLong(co + "");

					long lastValue = 0;
					if(b.getSelection()) {
						lastValue = curValue | (mark << offset);

					} else {
						lastValue = curValue ^ (mark << offset);

					}
					setFieldValue(target, beanPath[beanPath.length - 1], lastValue, filedClass);

				}

			});
		}
		addBeanListener(target, beanPath, checks, asc);

	}

	private int getCheckedCount(Button[] checks) {
		int cnt = 0;

		// 判断复选框初始已选中的数目是否小于cnt
		for(Button b : checks) {
			if(b.getSelection())
				cnt++;
		}
		return cnt;
	}

	protected void validateCheckBox(Button[] checks) {
		if(checks == null || checks.length == 0)
			throw new IllegalArgumentException("checks不能为空");
		for(Button b : checks) {
			if(b == null) {
				throw new IllegalArgumentException("checks中的元素不能为空");
			}
			if((b.getStyle() & SWT.CHECK) == 0) {
				throw new IllegalArgumentException("checks所包含的元素必须具有SWT.CHECK风格");
			}
		}
	}

	private static void setFieldValue(Object o, String fieldName, long value, Class<?> type) {
		Field f = null;
		try {
			f = o.getClass().getDeclaredField(fieldName);
			f.setAccessible(true);
			try {
				f.set(o, value);

			}
			catch(Exception e) {
				e.printStackTrace();

			}

		}
		catch(Exception e) {
			// e.printStackTrace();
			// 若没有名为fieldName的字段，那尝试调用setter
			String name = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
			Method setter = null;
			try {
				if(type.equals(long.class)) {
					setter = o.getClass().getMethod(name, long.class);
				} else if(type.equals(Long.class)){
					setter = o.getClass().getMethod(name, Long.class);
				}else{
					setter = o.getClass().getMethod(name, String.class);
				}
			}
			catch(Exception e1) {
				e1.printStackTrace();

			}
			try {
				if(type.equals(String.class)){
					setter.invoke(o, value+"");
				}else{
					setter.invoke(o, value);
				}
				

			}
			catch(Exception e1) {
				e1.printStackTrace();

			}

		}

	}

	protected Object computeBeanPropValue(Object bean, String[] beanPath) {
		if(beanPath.length == 1) {
			Object value = null;
			value = getFieldValue(bean, beanPath[0]);

			return value;
		} else {
			Object o = getFieldValue(bean, beanPath[0]);
			String[] newPath = new String[beanPath.length - 1];
			System.arraycopy(beanPath, 1, newPath, 0, beanPath.length - 1);
			return computeBeanPropValue(o, newPath);
		}
	}

	protected Object getFieldValue(Object o, String fieldName) {
		Object value = null;
		Field f = null;
		try {
			f = o.getClass().getDeclaredField(fieldName);
			filedClass = f.getType();
			f.setAccessible(true);
			try {
				value = f.get(o);
			}
			catch(Exception e) {
				e.printStackTrace();
			}

		}
		catch(Exception e) {
			// e.printStackTrace();
			// 若没有名为fieldName的字段，那尝试调用getter
			String name = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
			// parent.out(name + "\r\n");
			Method getter = null;
			try {
				getter = o.getClass().getMethod(name);
				filedClass = getter.getReturnType();
			}
			catch(Exception e1) {
				e1.printStackTrace();
			}
			try {
				value = getter.invoke(o);
			}
			catch(Exception e1) {
				e1.printStackTrace();

			}
			return value;
		}

		return value;
	}
}
